package com.qinker.robot.hook;

import android.app.Application;
import android.content.Context;
import android.util.Log;

import com.alibaba.fastjson.JSON;
import com.sky.xposed.common.util.Alog;

import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;

public class SearchMain implements IXposedHookLoadPackage {

    private Object globalSearchActivity = null;

    public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {

        if (!StringUtils.equals(Constant.Rimet.PACKAGE_NAME, lpparam.packageName)
                || !StringUtils.equals(Constant.Rimet.PACKAGE_NAME, lpparam.processName)) {
            return;
        }

     /*   XposedHelpers.findAndHookMethod("gyc", lpparam.classLoader, "a", String.class, new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                Log.i("DING_TEST", "进入方法: a@String");
                for (int j = 0; j < param.args.length; j++) {
                    Log.i("DING_TEST", "after" + (j + 1) + "个参数: " + JSON.toJSONString(param.args[j]));
                }
                Log.i(
                        "DING_TEST", "堆栈: ", new Exception());
            }
        });*/

        String className = "gxq$1";
        //Log.i("DING_TEST", "DING 进入HOOK1");
        //attachFindClass(className);
        Class<?> messageImpl = XposedHelpers.findClass(className, lpparam.classLoader);
        Log.i("DING_TEST", "DING 进入HOOK1" + messageImpl);
        Method[] methods = messageImpl.getDeclaredMethods();
        for (int i = 0; i < methods.length; i++) {
            int finali = i;
            if (filterMethod(methods[i])) {

                Log.i("DING_TEST", "hook method: " + methods[i].getName() + "@" + methods[i].getParameterTypes().length);
                XposedBridge.hookMethod(methods[i], new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        Log.i("DING_TEST", "进入方法: " + methods[finali].getName() + "@" + StringUtils.join(param.args, ","));
                        for (int j = 0; j < param.args.length; j++) {
                            Log.i("DING_TEST", "after" + (j + 1) + "个参数: " + JSON.toJSONString(param.args[j]));
                        }
                        Log.i(
                                "DING_TEST", "堆栈: ", new Exception());
                    }

                    @Override
                    protected void afterHookedMethod(MethodHookParam param) {

                    }
                });
            }
        }

        Log.i("DING_TEST", "调用搜索");
        //构建apiEventListener
        Class<?> suggestionGuidePresenterClass = XposedHelpers.findClass("gxq", lpparam.classLoader);
        Class<?> baseSearchPresenterClass = XposedHelpers.findClass("gwg", lpparam.classLoader);
        Class<?> searchQueryLogModelClass = XposedHelpers.findClass("gts", lpparam.classLoader);
        Class<?> apiEventListenerClass = XposedHelpers.findClass("gxq$1", lpparam.classLoader);
        Class<?> apiEventListenerSuperClass = XposedHelpers.findClass("dlf", lpparam.classLoader);

        Constructor<?> apiEventListenerClassDeclaredConstructor = apiEventListenerClass.getDeclaredConstructor(suggestionGuidePresenterClass, baseSearchPresenterClass, String.class, searchQueryLogModelClass);
        apiEventListenerClassDeclaredConstructor.setAccessible(true);
        Object apiEventListener = apiEventListenerClassDeclaredConstructor.newInstance(null, null, "SJ", null);

        Class<?> searchAPIImplClass = XposedHelpers.findClass("grj", lpparam.classLoader);

        Constructor<?> searchAPIImplClassDeclaredConstructor = searchAPIImplClass.getDeclaredConstructor();
        searchAPIImplClassDeclaredConstructor.setAccessible(true);
        Object searchApiImpl = searchAPIImplClassDeclaredConstructor.newInstance();

        Method aMethod = searchAPIImplClass.getDeclaredMethod("a", String.class, int.class, int.class, apiEventListenerSuperClass);

        aMethod.invoke(searchApiImpl, "SJ", 0, 3, apiEventListener);

        Log.i("DING_TEST", "DING 进入HOOK2");
    }


    private void attachFindClass(String strClazz) {
        XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                ClassLoader cl = ((Context) param.args[0]).getClassLoader();
                Class<?> clazz = cl.loadClass(strClazz);

                //XposedBridge.log("HookedClass : "+strClazz);
                // 获取到指定名称类声明的所有方法的信息
                Method[] m = clazz.getDeclaredMethods();
                // 打印获取到的所有的类方法的信息
                for (Method method : m) {

                    //XposedBridge.log("HOOKED CLASS-METHOD: "+strClazz+"-"+m[i].toString());
                    if (!Modifier.isAbstract(method.getModifiers())           // 过滤掉指定名称类中声明的抽象方法
                            && !Modifier.isNative(method.getModifiers())     // 过滤掉指定名称类中声明的Native方法
                            && !Modifier.isInterface(method.getModifiers())  // 过滤掉指定名称类中声明的接口方法
                    ) {

                        // 对指定名称类中声明的非抽象方法进行java Hook处理
                        XposedBridge.hookMethod(method, new XC_MethodHook() {

                            // 被java Hook的类方法执行完毕之后，打印log日志
                            @Override
                            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                                // 打印被java Hook的类方法的名称和参数类型等信息
                                Alog.i("HOOKED METHOD: " + strClazz + "-" + param.method.toString());
                            }
                        });
                    }
                }
            }
        });
    }

    private boolean filterMethod(Method method) {
        // 过滤掉指定名称类中声明的抽象方法
        return !Modifier.isAbstract(method.getModifiers())
                // 过滤掉指定名称类中声明的Native方法
                && !Modifier.isNative(method.getModifiers())
                // 过滤掉指定名称类中声明的接口方法
                && !Modifier.isInterface(method.getModifiers())
                && !("decode".equals(method.getName()))
                && !("getClass".equals(method.getName()))
                && !("equals".equals(method.getName()))
                && !("clone".equals(method.getName()))
                && !("hashCode".equals(method.getName())
                && !("toString".equals(method.getName()))
                && !("wait".equals(method.getName())));
    }
}


